import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs-extra';
import * as _fs from 'fs';
import * as os from 'os';
import { getComponentTemplates } from './component_templates';

const EOL = os.EOL;

export class OdooMisc {
    private context: vscode.ExtensionContext;

    constructor(context: vscode.ExtensionContext) {
        this.context = context;
    }

    async getTemplatesPath() {
        return path.join(this.context.extensionPath, 'templates');
    }

    async createModule(
        { name, destDir, odooVersion, hasWebModule }:
        { name: string; destDir: string; odooVersion: string, hasWebModule: string}) {
        try {
            const tmplsPath = await this.getTemplatesPath();
            const newModulePath = path.join(destDir, name);
            await fs.copy(tmplsPath, newModulePath);
            fs.ensureDir(path.join(newModulePath, 'static', 'description'))
            if(hasWebModule === '是') {
                this.createWebModule(newModulePath, name, odooVersion)
                // odoo14中使用的前端文件，需要在xml中引入
                if(odooVersion === '14') {
                    this.createAssets(newModulePath, name)
                }
            }
            this.createManifest(name, newModulePath, odooVersion, hasWebModule)
        } catch (error) {
            console.log(error);
        }
    }

    ensureSrcDir(modulePath: string) {
        const srcDirPath = path.join(modulePath, 'static', 'src');
        fs.ensureDir(srcDirPath);
        return srcDirPath;
    }

    createService(serviceName:string, filenName:string, modulePath: string) {
        const jsTemplate = `/** @odoo-module */

import { registry } from "@web/core/registry";

export const ${serviceName} = {
    dependencies: ["rpc", "orm"],
    async start(env, { rpc, orm }) {

        return {  };
    },
};

registry.category("services").add("${serviceName}", ${serviceName});`
        const srcDirPath = this.ensureSrcDir(modulePath)
        const serviceFilePath = path.join(srcDirPath, 'services', filenName+'.js')
        fs.ensureFile(serviceFilePath).then(() => {
            fs.writeFile(serviceFilePath, jsTemplate);
        });
    }

    createComponent(componentName:string, filenName:string, componentType:string, modulePath: string) {
        const srcDirPath = this.ensureSrcDir(modulePath)
        const componentPath = path.join(srcDirPath, 'components', filenName)
        const moduleName = path.basename(modulePath);
        const { jsTemplate, xmlTemplate } = getComponentTemplates(componentName, filenName, componentType, moduleName);

        const jsFilePath = path.join(componentPath, filenName+'.js');
        const xmlFilePath = path.join(componentPath, filenName+'.xml');
        const scssFilePath = path.join(componentPath, filenName+'.scss');
        fs.ensureFile(jsFilePath).then(() => {
            fs.writeFile(jsFilePath, jsTemplate);
        });
        fs.ensureFile(xmlFilePath).then(() => {
            fs.writeFile(xmlFilePath, xmlTemplate);
        });
        fs.ensureFile(scssFilePath);
    }

    createWebModule(modulePath: string, moduleName: string, odooVersion: string,) {
        const srcDirPath = this.ensureSrcDir(modulePath)
        if(odooVersion === '16') {
            // 16版本将组件js/scss/xml存放到一个目录下
            return
        }
        const jsFilePath = path.join(srcDirPath, 'js', moduleName+'.js');
        const jsFileContent = `odoo.define('${moduleName}', function (require) {
    'use strict';
    const { Component } = owl;
    const { useRef, useState, onWillStart, onMounted } = owl.hooks;
    const { ComponentWrapper } = require('web.OwlCompatibility');

    const core = require('web.core');
    const AbstractAction = require('web.AbstractAction');
    const AbstractField = require('web.AbstractFieldOwl');
    const fieldRegistry = require('web.field_registry_owl');
    const AbstractRendererOwl = require("web.AbstractRendererOwl");
    const patchMixin = require("web.patchMixin");

});
        `;
        fs.ensureFile(jsFilePath).then(() => {
            fs.writeFile(jsFilePath, jsFileContent);
        });

        const xmlFilePath = path.join(srcDirPath, 'xml', moduleName+'.xml');
        const xmlFileContent = `<?xml version="1.0" encoding="utf-8"?>
<templates>
    <t t-name="" owl="1">
    </t>
</templates>
        `;
        fs.ensureFile(xmlFilePath).then(() => {
            fs.writeFile(xmlFilePath, xmlFileContent)
        });

        const scssFilePath = path.join(srcDirPath, 'scss', moduleName+'.scss');
        fs.ensureFile(scssFilePath)
    }

    createManifest(moduleName: string, modulePath: string, odooVersion: string, hasWebModule: string) {
        const filePath = path.join(modulePath, '__manifest__.py');
        let assetsFilePath = '';
        let qwebFielPath = '';
        let assets = '';
        if(hasWebModule === '是') {
            switch (odooVersion) {
                case '14':
                    assetsFilePath = `'views/assets.xml',${EOL}\t\t`;
                    qwebFielPath = `${EOL}\t'qweb': ['static/src/xml/${moduleName}.xml'],`;
                    break;
                case '15':
                    assets = `
    'assets': {
        'web.assets_backend': [
            '${moduleName}/static/src/scss/*.scss',
            '${moduleName}/static/src/js/*.js'
        ],
        'web.assets_qweb': [
            '${moduleName}/static/src/xml/*.xml',
        ],
    },`
                    break;
                case '16':
                    assets = `
    'assets': {
        'web.assets_backend': [
            '${moduleName}/static/src/**/*'
        ],
    },`
                    break;
                default:
                    break;
            }
        }
        const manifestContent = `{
    'name': '',
    'version': '${odooVersion}.0.1.0.0',
    'category': '',
    'license': 'LGPL-3',
    'description': """
功能介绍
==============

*
    """,
    'author': '',
    'website': '',
    'depends': ['base'],
    'data': [
        ${assetsFilePath}'security/ir.model.access.csv'
    ],${qwebFielPath}${assets}
    'application': True,
    'installable': True,
    'auto_install': False,
}
        `
        fs.writeFile(filePath, manifestContent);
    }

    createAssets(modulePath: string, moduleName: string) {
        const filePath = path.join(modulePath, 'views', 'assets.xml');
        const assetsFileContent = `<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <template id="assets_backend" inherit_id="web.assets_backend">
        <xpath expr="." position="inside">
            <link rel="stylesheet" href="/${moduleName}/static/src/scss/${moduleName}.scss"/>
            <script type="text/javascript" src="/${moduleName}/static/src/js/${moduleName}.js"></script>
        </xpath>
    </template>
</odoo>
        `;
        fs.ensureFile(filePath).then(() => {
            fs.writeFile(filePath, assetsFileContent);
        });

    }

    updateManifestDataKey(modulePath: string, newData: string) {
        const filePath = path.join(modulePath, '__manifest__.py');
        return fs.readFile(filePath).then((data) => {
            // 使用非贪婪模式.*?可以防止匹配到assets对应的 ]
            // let dataKeyRe = /(\'|\")data.*?\[.*?\]/gis;

            // 文心一言给出的正则表达式，稍微改了一下
            // 这个正则表达式使用了 [\s\S]*? 来匹配任意字符，包括换行符。*? 表示非贪婪匹配，它会尽可能少地匹配字符。
            // 这样，正则表达式会匹配以 'data': [' 开头，以 '] 结尾的任意行。
            let dataKeyRe = /(\'|\")data[\s\S]*?]/g
            let fileContent = data.toString();
            let dataKey = fileContent.match(dataKeyRe);
            let dataKeyStr = dataKey && dataKey[0].replace(/\'/gis, `"`);
            let dataKeyMap = JSON.parse(`{${dataKeyStr}}`);
            dataKeyMap['data'].unshift('views/' + newData);
            let x = JSON.stringify(dataKeyMap, null, 4).slice(1, -2).trim();
            fileContent = fileContent.replace(dataKeyRe, x);
            fs.writeFile(filePath, fileContent);
        });
    }

    updateInitFile(modulePath: string, importName:string) {
        const filePath = path.join(modulePath, 'models', '__init__.py');
        fs.writeFile(filePath, `from . import ${importName}` + os.EOL, { 'flag': 'a' });
    }

    updateSecurityCsv(modulePath: string, modelName: string) {
        const filePath = path.join(modulePath, 'security', 'ir.model.access.csv');
        let acs = [
            `access_${modelName}_user,${modelName}_user,model_${modelName},,1,1,1,0`,
            `access_${modelName}_manager,${modelName}_manager,model_${modelName},,1,1,1,1`,
            `,,,,,,,`];
        const data = acs.map((val) => {
            return val+os.EOL;
        });
        fs.writeFile(filePath, data.join(''), { 'flag': 'a' });
    }

    createNewModel(modelName: string, modulePath: string) {
        const modelNames: string[] = modelName.split('.');
        const pyFileName = modelNames.join('_') + '.py';
        const xmlFileName = modelNames.join('_') + '_views.xml';
        const pyFilePath = path.join(modulePath, 'models', pyFileName);
        const xmlFilePath = path.join(modulePath, 'views', xmlFileName);
        const tmpls = this.getNewModelTemplates(modelName);
        // 创建新模型的py、xml文件，根据名称填充文件内容
        fs.ensureFile(pyFilePath).then(() => {
            fs.writeFile(pyFilePath, tmpls.pyFileTemplate);
        });
        fs.ensureFile(xmlFilePath).then(() => {
            fs.writeFile(xmlFilePath, tmpls.xmlFileTemplate);
        });
        // 更新清单文件、__init__文件、ir.model.access.csv文件
        this.updateManifestDataKey(modulePath, xmlFileName);
        this.updateInitFile(modulePath, modelNames.join('_'));
        this.updateSecurityCsv(modulePath, modelNames.join('_'));
    }

    createInheritModel(modelName:string, modulePath: string) {
        // 创建文件、写入内容、更新init
        const modelNames: string[] = modelName.split('.');
        const pyFileName = 'inherited_'+modelNames.join('_') + '.py';
        const pyFilePath = path.join(modulePath, 'models', pyFileName);
        const pyTmpl = this.getInheritModelTemplates(modelName);
        fs.ensureFile(pyFilePath).then(() => {
            fs.writeFile(pyFilePath, pyTmpl);
        });
        this.updateInitFile(modulePath, 'inherited_'+modelNames.join('_'));
    }

    getInheritModelTemplates(modelName: string) {
        const modelNames: string[] = modelName.split('.');
        const className = modelNames.map((val) => {
            return val[0].toUpperCase() + val.substring(1, val.length);
        }).join('');

        const pyFileTemplate: string = `import logging

from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError

_logger = logging.getLogger(__name__)


class ${className}(models.Model):
    """
    """
    _inherit = '${modelName}'
        `;
        return pyFileTemplate;
    }

    getNewModelTemplates(modelName: string): { pyFileTemplate: string, xmlFileTemplate: string } {
        const modelNames: string[] = modelName.split('.');
        const _modeName = modelNames.join('_');
        const className = modelNames.map((val) => {
            return val[0].toUpperCase() + val.substring(1, val.length);
        }).join('');
        const pyFileTemplate: string = `import logging

from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError

_logger = logging.getLogger(__name__)


class ${className}(models.Model):
    """
    """
    _name = '${modelName}'
    _description = ''
        `;
        const xmlFileTemplate: string = `<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <!-- ${modelName} 列表视图 -->
    <record id="${_modeName}_view_tree" model="ir.ui.view">
        <field name="name">${modelName}.view.tree</field>
        <field name="model">${modelName}</field>
        <field name="arch" type="xml">
            <tree>

            </tree>
        </field>
    </record>
    <!-- ${modelName} 表单视图 -->
    <record id="${_modeName}_view_form" model="ir.ui.view">
        <field name="name">${modelName}.view.form</field>
        <field name="model">${modelName}</field>
        <field name="arch" type="xml">
            <form string="">
                <header></header>
                <sheet>
                    <group string="隐藏字段" invisible="1">
                        <field name="id"/>
                    </group>
                    <group>
                        <group>

                        </group>
                        <group>
                        </group>
                    </group>
                </sheet>
            </form>
        </field>
    </record>
    <!-- ${modelName} 搜索视图 -->
    <record id="${_modeName}_view_search" model="ir.ui.view">
        <field name="name">${modelName}.view.search</field>
        <field name="model">${modelName}</field>
        <field name="arch" type="xml">
            <search string="">
                <field name=""/>
                <filter string="当前月份" name="this_month" domain="[('时间字段', '&gt;=', context_today().strftime('%Y-%m-01'))]"/>
            </search>
        </field>
    </record>
    <!-- ${modelName}.act_window -->
    <record id="${_modeName}_action" model="ir.actions.act_window">
        <field name="name"></field>
        <field name="type">ir.actions.act_window</field>
        <field name="res_model">${modelName}</field>
        <field name="view_mode">tree,form</field>
        <field name="target">current</field>
    </record>
</odoo>
        `;
        return { pyFileTemplate, xmlFileTemplate };
    }

}